package gazpachito.examples.patterns.methodTemplate.business.vehicle;

import gazpachito.examples.patterns.methodTemplate.api.EngineVehicleDTO;
import gazpachito.examples.patterns.methodTemplate.api.VehicleDTO;
import gazpachito.examples.patterns.methodTemplate.business.TemplateBusiness;
import gazpachito.examples.patterns.methodTemplate.business.exceptions.BusinessException;
import gazpachito.examples.patterns.methodTemplate.utils.MessageUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

/**
 * This abstract class contains all the business rules are commons for all the
 * different kinds of vehicles.
 * 
 * @author jvillar
 * 
 */
public abstract class AbstractVehicleBusinessImpl<T extends VehicleDTO>
		implements TemplateBusiness<VehicleDTO> {

	Map<Integer, VehicleDTO> storedVehicles = new HashMap<Integer, VehicleDTO>();

	public AbstractVehicleBusinessImpl() {
		super();

		EngineVehicleDTO vehicle = new EngineVehicleDTO();

		vehicle.setIdVehicle(1);
		vehicle.setName("125cc Motorbike");
		vehicle.setDescription("Motorbike with the power limited to 125");
		vehicle.setcV(new BigDecimal("125.00"));

		storedVehicles.put(vehicle.getIdVehicle(), vehicle);

	}

	@Override
	public void validate(VehicleDTO element) throws BusinessException {

		if (element == null) {
			throw new BusinessException(
					MessageUtils
							.getMessage(MessageUtils.ERROR_VEHICLE_NOT_INFORMED));
		}
		if (StringUtils.isBlank(element.getName())) {
			throw new BusinessException(
					MessageUtils
							.getMessage(MessageUtils.ERROR_VEHICLE_NAME_ISEMPTY));
		}

		if (StringUtils.isBlank(element.getDescription())) {
			throw new BusinessException(
					MessageUtils
							.getMessage(MessageUtils.ERROR_VEHICLE_DESCRIPTION_ISEMPTY));
		}

		try {
			this.validateConcrete(element);
		} catch (ClassCastException c) {
			throw new BusinessException(
					MessageUtils
							.getMessage(MessageUtils.ERROR_ELEMENT_NOT_COMPATIBLE));
		}

	}

	@Override
	public void execute(VehicleDTO element) throws BusinessException {

		if (element.getIdVehicle() != null
				&& storedVehicles.containsKey(element.getIdVehicle())) {
			throw new BusinessException(
					MessageUtils.getMessage(MessageUtils.ERROR_ELEMENT_EXIST));
		}

		List<Integer> keysStored = new ArrayList<Integer>(
				this.storedVehicles.keySet());

		Collections.sort(keysStored, new Comparator<Integer>() {

			@Override
			public int compare(Integer o1, Integer o2) {

				return o1.compareTo(o2);
			}
		});

		element.setIdVehicle(keysStored.get(keysStored.size() - 1) + 1);

		try {
			this.executeConcrete(element);
		} catch (ClassCastException c) {
			throw new BusinessException(
					MessageUtils
							.getMessage(MessageUtils.ERROR_ELEMENT_NOT_COMPATIBLE));
		}

	}

	public abstract void validateConcrete(VehicleDTO vehicle)
			throws BusinessException;

	public abstract void executeConcrete(VehicleDTO vehicle);

	public Map<Integer, VehicleDTO> getStoredVehicles() {
		return storedVehicles;
	}

	public void setStoredVehicles(Map<Integer, VehicleDTO> storedVehicles) {
		this.storedVehicles = storedVehicles;
	}

}
